package com.example.chess.api;

import com.example.chess.game.Matcher;
import com.example.chess.game.OnlineUserManager;
import com.example.chess.game.Room;
import com.example.chess.game.RoomManager;
import com.example.chess.model.User;
import com.example.chess.util.MatchRequest;
import com.example.chess.util.MatchResponse;
import com.example.chess.util.ResState;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import javax.annotation.Resource;

/**
 * 处理匹配的 webSocket请求
 */
@Component
public class MatchAPI extends TextWebSocketHandler {

    private ObjectMapper objectMapper = new ObjectMapper();

    @Resource
    private OnlineUserManager onlineUserManager;// 将会话管理类注入

    @Resource
    private Matcher matcher;// 匹配队列管理器

    @Resource
    private RoomManager roomManager;

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        // 建立连接  --  玩家上线
        User user = (User)session.getAttributes().get("user");// 得到当前的 user对象
        if (user == null){
            //          TestMessage:  文本格式数据报
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(
                            new MatchResponse(ResState.FAIL, "尚未登录", ""))));
            return;
        }
        if (onlineUserManager.getRoomSession(user.getUserId()) != null ||
                onlineUserManager.getSession(user.getUserId()) != null){
            // 已经在其他地方登录了, 不能登录
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(
                            new MatchResponse(ResState.EXIST, "禁止多地登陆", ""))));
            session.close();// 断开当前连接
            return;
        }

        onlineUserManager.enterGame(user.getUserId(), session);// 存储进游戏大厅队列
        System.out.println(user.getNickname() + " 进入游戏大厅!");
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        // 开始匹配 / 停止匹配
        User user = (User)session.getAttributes().get("user");
        // 获取数据载荷
        String payload = message.getPayload();
        // 解析为对象
        MatchRequest request = objectMapper.readValue(payload, MatchRequest.class);
        if (request.getMessage().equals("startMatch")){
            // 添加到匹配队列
            matcher.enterQueue(user);

            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(
                            new MatchResponse(ResState.SUCCESS,"添加到匹配队列成功","startMatch"))));
        }else if (request.getMessage().equals("stopMatch")){
            // 从匹配队列移出
            matcher.quit(user);

            session.sendMessage(new TextMessage(
                    objectMapper.writeValueAsString(
                            new MatchResponse(ResState.SUCCESS,"移除匹配队列成功","stopMatch"))));
        }else if (request.getMessage().equals("challenge")) {
            // 是要向别人发出挑战
            int thatUserId = request.getUserId();// 拿到要挑战的用户的 id
            // 看对方是否   不在线 / 或者已经在游戏中
            if (onlineUserManager.getSession(thatUserId) == null){
                session.sendMessage(new TextMessage(objectMapper.writeValueAsString(
                        new MatchResponse(ResState.FAIL, "outline", "challenge")
                )));
                return;
            }
            if (onlineUserManager.getRoomSession(thatUserId) != null){
                session.sendMessage(new TextMessage(objectMapper.writeValueAsString(
                        new MatchResponse(ResState.FAIL, "game", "challenge")
                )));
                return;
            }
            // 将对方可以邀请的状态给当前用户
            MatchResponse response = new MatchResponse(ResState.SUCCESS, "等待对方接受邀请", "challenge");
            response.setUserId(thatUserId);
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
            // 给对方发消息, 让他接受邀请
            // 找到对方的session
            WebSocketSession thatUserSession = onlineUserManager.getSession(thatUserId);
            MatchResponse response2 = new MatchResponse(ResState.SUCCESS, user.getNickname(), "waitAccept");
            response2.setUserId(user.getUserId());// 将挑战者的 Id也传过去
            thatUserSession.sendMessage(new TextMessage(objectMapper.writeValueAsString(response2)));

            System.out.println(user.getUserId() + "向" + thatUserId + "发起挑战");

        }else if (request.getMessage().equals("acceptChallenge")){
            // 接受挑战
            int thatUserId = request.getUserId();// 拿到向我方发起挑战的用户的 id
            int thisUserId = user.getUserId();// 我方 Id
            // 将两个人放到一个房间内
            Room room = new Room();
            roomManager.add(room, thisUserId, thatUserId);
            // 给双方发送消息
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(
                    new MatchResponse(ResState.SUCCESS, "匹配成功", "matchSuccess"))));
            WebSocketSession session2 = onlineUserManager.getSession(thatUserId);
            session2.sendMessage(new TextMessage(objectMapper.writeValueAsString(
                    new MatchResponse(ResState.SUCCESS, "匹配成功", "matchSuccess"))));
        }else if (request.getMessage().equals("refuseChallenge")) {
            // 拒绝了对方的邀请
            int thatUserId = request.getUserId();
            WebSocketSession session1 = onlineUserManager.getSession(thatUserId);
            MatchResponse response = new MatchResponse(ResState.SUCCESS, "拒绝了你的邀请", "refuseChallenge");
            response.setUserId(user.getUserId());// 将拒绝方的 id发过去
            session1.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        }else if (request.getMessage().equals("watch")){
            String roomId = request.getRoomId();// 拿到房间号
            // 找到房间
            Room room = roomManager.getRoomById(roomId);
            if (room == null){
                session.sendMessage(new TextMessage(objectMapper.writeValueAsString(
                        new MatchResponse(ResState.FAIL, "notExit", "watch"))));
                return;
            }
            // 加入总的观战列表里
            roomManager.enterWatch(user.getUserId(), roomId);

            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(
                    new MatchResponse(ResState.SUCCESS, roomId, "watch"))));
            return;
        }else {
            session.sendMessage(new TextMessage(
                    objectMapper.writeValueAsString(
                            new MatchResponse(ResState.FAIL,"非法请求", ""))));
        }
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        // 玩家下线
        User user = (User)session.getAttributes().get("user");// 得到当前的 user对象
        if (user == null){
            System.out.println("未登录!");
            return;
        }
        // 当触发多地登陆时, 在关闭了当前的webSocketSession后, 会触发这个方法, 为了防止将正常连接的也关闭了
        WebSocketSession tempSession = onlineUserManager.getSession(user.getUserId());
        if (tempSession == session){
            // 是当前会话
            onlineUserManager.outGame(user.getUserId());// 退出游戏大厅
        }
        // 从匹配队列移出
        matcher.quit(user);
        System.out.println(user.getNickname() + " 退出游戏大厅!");
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        // 玩家下线
        User user = (User)session.getAttributes().get("user");// 得到当前的 user对象
        if (user == null){
            System.out.println("未登录!");
            return;
        }
        // 当触发多地登陆时, 在关闭了当前的webSocketSession后, 会触发这个方法, 为了防止将正常连接的也关闭了
        WebSocketSession tempSession = onlineUserManager.getSession(user.getUserId());
        if (tempSession == session){
            // 是当前会话
            onlineUserManager.outGame(user.getUserId());// 退出游戏大厅
        }
        // 从匹配队列移出
        matcher.quit(user);
        System.out.println(user.getNickname() + " 退出游戏大厅!");
    }
}
